﻿using System;
using Phoenix.Xna.Framework.ContentPipeline;
using Phoenix.Xna.Framework.Graphics;
using Phoenix.Xna.Framework.Serialization;
using Microsoft.Xna.Framework.Graphics;

namespace Phoenix.Xna.Framework
{
    /// <summary>
    /// A wrapper for data that can have meta-data and an ID.  This wrapper also provides functionality to load it's value from
    /// the content pipeline.
    /// </summary>
    public class ValueBinding : IHasContent
    {
        /// <summary>
        /// Gets or sets the value this binding contains.
        /// </summary>
        [SerializableProperty(null)]
        public virtual object Value { get; set; }

        /// <summary>
        /// Gets of sets the ID of this binding.
        /// </summary>
        [SerializableProperty("")]
        public virtual string ID { get; set; }

        /// <summary>
        /// Gets or sets any meta-data associated with this binding.
        /// </summary>
        [SerializableProperty("")]
        public string MetaData { get; set; }

        /// <summary>
        /// Gets the System.Type of the value of this binding.
        /// </summary>
        /// <returns></returns>
        public Type GetValueType()
        {
            return Value.GetType();
        }

        /// <summary>
        /// Sets the value of the binding.
        /// </summary>
        /// <typeparam name="T">The type of object this binding contains.</typeparam>
        /// <param name="value">The value to set the binding to.</param>
        public void SetValue<T>(T value)
        {
            Value = value;
        }

        /// <summary>
        /// Gets the value of the binding as the specifiec type T.
        /// </summary>
        /// <typeparam name="T">The type to try to cast the value to.</typeparam>
        /// <returns>The value of the binding as type T.</returns>
        public T GetValue<T>()
        {
            return (T)Value;
        }

        /// <summary>
        /// Gets a boolean indicating that the type of the binding of of type T.
        /// </summary>
        /// <typeparam name="T">The type to compare the value type to.</typeparam>
        /// <returns>True if the value is of type T, otherwise false.</returns>
        public bool Is<T>()
        {
            return (Value is T) ? true : false;
        }

        #region Object Members

        /// <summary>
        /// The value of the binding as a string.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (ContentHelper.IsLoadableType(Value.GetType()))
            {
                return MetaData;
            }
            else
            {
                return StringHelper.ObjectToString(Value);
            }
        }

        #endregion

        #region IHasContent Members

        /// <summary>
        /// Gets a value indicating the content for the instance has been loaded.
        /// </summary>
        public bool IsContentLoaded { get; private set; }

        /// <summary>
        /// Loads any graphics related content from the content pipeline.
        /// </summary>
        public virtual void LoadContent()
        {
            if (Value is string)
            {
                Type type = Type.GetType(Value as string);

                if (type != null)
                {
                    Value = ContentHelper.Load(type, MetaData);
                }
            }

            IsContentLoaded = true;
        }

        /// <summary>
        /// Unloads any graphics related content from the content pipeline.
        /// </summary>
        public virtual void UnloadContent()
        {
            ContentHelper.Unload(MetaData);
            Value = null;
            IsContentLoaded = false;
        }

        #endregion
    }
}
